home *** CD-ROM | disk | FTP | other *** search
- /*
- * HD Runner: An application that scans the desktop to retrieve the names and locations of
- * all applications on HFS volumes, and offers a scrolling list for launching.
- * Author: Dewi Williams Delphi: dewi, CompuServe 73210,132.
- * Status: Explicitly in public domain. Please keep the application, source and
- * documentation together when distributing.
- * Limitations: ignores MFS volumes.
- * Build: Lightspeed C, version 2.01. Needs Lightspeed's qsort.c
- * Version: 1.0
- */
-
- #include <pascal.h>
- #include <MacTypes.h>
- #include <QuickDraw.h>
- #include <ResourceMgr.h>
- #include <MenuMgr.h>
- #include <MemoryMgr.h>
- #include <FileMgr.h>
- #include <HFS.h>
- #include <ToolboxUtil.h>
- #include <EventMgr.h>
- #include <ListMgr.h>
- #include <DialogMgr.h>
- #include <StdFilePkg.h>
- #include <OSUtil.h>
- #include <SegmentLdr.h>
-
- /* Low memory globals */
- extern int ROM85 : 0x28E; /* ROM Version */
- extern int mBarHeight : 0xBAA; /* menu bar height: 128K ROMs and onwards... */
-
- /* A define to test for a 64K ROM. */
- #define has64K (ROM85&0x8000)
-
- /* A define to calculate the height of the menu bar. */
- #define mbHeight ((has64K) ? 20 : mBarHeight)
-
- /* These two are more efficient than using the Toolbox equivalents. */
- #define HiWord(x) (((unsigned short *)&(x))[0])
- #define LoWord(x) (((unsigned short *)&(x))[1])
-
- /* LPOINT: macro that coerces a point into a long and vice versa. */
- #define LPOINT(pt) (*((long*)&pt))
-
- #define MIN(a,b) ((a < b) ? a : b)
-
- /* A define to round up to an even number. */
- #define EVEN(x) (( (x + 1) >> 1) << 1)
-
- #define NAME_SIZE 32 /* Maximum Finder name length */
- #define NULL 0L
-
- /* A define to skip around the variable-length ESTR in the APPL resource. */
- #define NEXT_APPL(a) ((Appl *)(EVEN( (ulong)(&a->name + a->name[0] + 1))))
-
- /* Resource identities */
- #define R_DLOG 128 /* The dialog box */
- #define R_CORRUPT 129 /* The bad desktop alert */
- #define R_NOHFS 130 /* The MFS File Manager is active alert */
- #define R_VOLPROBS 131 /* Something's wrong with volumes. */
- #define R_DESKTOP 128 /* The "Desktop" string */
- #define R_FINDER 129 /* The "Finder" string */
- #define R_ABOUT 132 /* The "About HD Runner..." dialog box */
- #define R_MENUBAR 256 /* The MBAR resource. */
- #define R_READING 133 /* "Reading desktop file..." dialog box */
- #define R_CONFIG 128 /* The 'GNRL' config resource. */
-
- /* Menu IDs */
- #define M_ABOUT 256
- #define M_FILE 257
- #define M_EDIT 258
-
- /* Dialog item numbers for the modeless dialog. */
- #define I_RUN 1
- #define I_QUIT 2
- #define I_OUTLINE 3
- #define I_APPS 4
- #define I_MINIFINDER 5
- #define I_DOCS 6
-
- /* And for the "About" dialog. */
- #define I_ABOUTOUTLN 5
-
- /* Cursor keys */
- #define cursUp 0x1e
- #define cursDown 0x1f
-
- /* Types */
- typedef unsigned long ulong;
-
- /* The layout of the 'APPL' resource in the desktop, as determined from TechNote #29,
- * and confirmed by looking at its 'TMPL' resource.
- */
- typedef struct {
- ResType creator;
- long dir;
- unsigned char name[1];
- } Appl, **ApplHandle;
-
- /* The application table entry. Essentially, it's just the Appl struct above with a fixed size name
- * field to make sorting easier.
- */
- typedef struct {
- int volID;
- ResType creator;
- long dir;
- unsigned char name[NAME_SIZE];
- } FullAppl;
-
- /*
- * The AppParmHandle layout for a single attached document.
- */
- typedef struct {
- int message;
- int count;
- AppFile a;
- } OneArg;
-
- /* Forward references */
- Handle _Get1Resource(ResType, int);
- int appCompare(FullAppl *, FullAppl *);
- DialogPtr DispChooseApp();
- pascal void ListDraw();
- int StartsWith(Byte);
- void Quit(void);
- pascal Boolean ListFileFilter(ParmBlkPtr p);
- void SetupDAs(void);
- int DoCommand(long mResult);
- int DoChar(DialogPtr dPtr, unsigned char theChar);
- void About(void);
- int EventLoop(DialogPtr, EventRecord *);
-
- /* Globals */
- int theSelection = 0; /* index of currently selected application */
- int numApps; /* number of applications in list */
- Rect box; /* scrolling list's outline */
- ListHandle lh; /* List Manager handle */
- FullAppl *apps = NULL; /* The application table. */
- char fName[20]; /* Holds finder name retrieved from the R_FINDER 'STR ' */
- Byte miniFinder; /* Is the Finder active? */
- Handle mHandle; /* Handle to the menu bar. */
-
- main()
- {
- int rsrc;
- ApplHandle aH;
- register Appl *a;
- register Appl *end;
- register FullAppl *copy;
- Str255 name;
- register int i;
- int itemHit;
- OSErr err;
- WDPBRec pb;
- HParamBlockRec v;
- VolumeParam vparm;
- int volNo;
- StringHandle desktop, finder;
- Handle config;
- int volApps;
- CursHandle watch;
- int op;
- SFReply reply;
- Point pt;
- DialogPtr dPtr;
- EventRecord evRec;
- DialogPtr reading;
- int doDeskDialog;
-
- /* Initialize the various managers. */
- InitGraf(&thePort);
- InitFonts();
- FlushEvents( everyEvent, 0 );
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(0L);
- InitCursor();
- MaxApplZone();
- SetupDAs();
-
- if (FSFCBLen == -1) { /* Is the HFS File Manager active? */
- StopAlert(R_NOHFS, (ProcPtr)NULL);
- ExitToShell();
- }
-
- if ( (finder = (StringHandle)GetResource('STR ', R_FINDER)) == NULL) {
- /* ResEdit fiend on the loose? */
- SysBeep(5);
- ExitToShell();
- }
-
- BlockMove(*finder, fName, **finder +1);
- ReleaseResource(fName);
-
- /* Is the finder active? */
- if ((miniFinder = IUEqualString(fName, FinderName)) != 0) {
- /* Somebody's intercepting, but is it us? */
- if (IUEqualString(FinderName, CurApName) != 0) {
- /* Somebody else. miniFinder's cleared, and arrangements made to quit back to
- * this guy, rather than the finder. This means that you can run HD Runner
- * under Oasis, and then go back to Oasis afterwards.
- */
- BlockMove(FinderName, fName, FinderName[0] +1);
- miniFinder = 0;
- }
- }
-
- if ( (config = GetResource('GNRL', R_CONFIG)) == NULL)
- doDeskDialog = 0;
- else
- doDeskDialog = **config;
-
- if (doDeskDialog) {
- reading = GetNewDialog(R_READING, (Ptr)NULL, (WindowPtr)-1);
- DrawDialog(reading); /* so that the string gets drawn. */
- }
-
- if ( (desktop = (StringHandle)GetResource('STR ', R_DESKTOP)) == NULL) {
- /* ResEdit fiend on the loose? */
- SysBeep(5);
- Quit();
- }
-
- HNoPurge(desktop); /* just in case */
- numApps = 0;
-
- if ( (watch = GetCursor(watchCursor)) != NULL) SetCursor(*watch);
-
- /* Run through all mounted volumes. */
- for(volNo =1;; volNo++) {
- v.volumeParam.ioCompletion = NULL;
- v.volumeParam.ioNamePtr = NULL;
- v.volumeParam.ioVolIndex = volNo;
- v.volumeParam.ioVRefNum = 0;
-
- err = PBHGetVInfo(&v, FALSE);
-
- if (err == nsvErr) break; /* Run through all the mounted volumes. */
-
- if (err != noErr) { /* Something's twisted. */
- StopAlert(R_VOLPROBS, (ProcPtr)NULL);
- Quit();
- }
-
- /* Validate the volume as online, HFS. */
- if(v.volumeParam.ioVSigWord != 0x4244) continue; /* skip MFS */
-
- if(v.volumeParam.ioVDRefNum >= 0) continue; /* offline */
-
- /* This volume passes the tests. Let's go for its desktop file. Go for root. */
- pb.ioCompletion = NULL;
- pb.ioNamePtr = NULL;
- pb.ioVRefNum = v.volumeParam.ioVRefNum;
-
- if (PBSetVol(&pb, FALSE) != noErr) {
- /* No such volume? I suspect that things are twisted, and there's no point
- * in continuing.
- */
- StopAlert(R_VOLPROBS, (ProcPtr)NULL);
- Quit();
- }
-
- HLock(desktop);
- SetResLoad(FALSE);
- if ( (rsrc = OpenResFile(*desktop)) == -1) {
- /* Finder hasn't put a desktop on this volume yet? */
- SetResLoad(TRUE);
- HUnlock(desktop);
- continue;
- }
- HUnlock(desktop);
-
- if ( (aH =(ApplHandle) _Get1Resource('APPL', 0)) == NULL) {
- /* Is this a corrupt desktop? Skip it for now, since it may just be a new
- * disk.
- */
- SetResLoad(TRUE);
- CloseResFile(rsrc);
- continue;
- }
-
- SetResLoad(TRUE);
- LoadResource(aH);
-
- HLock(aH);
- end = (Appl *) ( (char *)*aH + GetHandleSize(aH));
-
- /* How many are there? */
- for(a = *aH, volApps = 0; a < end;a = NEXT_APPL(a)) {
- volApps++; /* total, this volume */
- }
-
- /* Get ready to copy to our application table. We do what's usually a major no-no,
- * and grow non-relocatables. This is a controlled environment where we can get
- * away with it (Famous last words...)
- */
- if (apps == NULL) { /* First time */
- if ( (apps = (FullAppl *)NewPtr((Size)(volApps * sizeof(FullAppl)))) == NULL) {
- SysBeep(10);
- CloseResFile(rsrc);
- Quit();
- }
- } else { /* Grow it. */
- SetPtrSize(apps, (Size)((numApps + volApps) * sizeof(FullAppl)));
- if (MemErr != noErr) {
- SysBeep(10);
- CloseResFile(rsrc);
- Quit();
- }
- }
-
- /* Copy over the application data to the application table */
- for(a = *aH, i = numApps, copy = apps + numApps; a < end;a = NEXT_APPL(a), copy++) {
- copy->volID = v.volumeParam.ioVRefNum;
- BlockMove(a, ©->creator, (Size)(sizeof(Appl) + a->name[0]));
- }
-
- numApps += volApps; /* total, all volumes */
-
- /* Can close this desktop now */
- HUnlock(aH);
- ReleaseResource(aH);
- CloseResFile(rsrc);
- }
-
- /* Did we find any applications on online HFS volumes? */
- if (numApps == 0) Quit();
-
- /* And quicksort them. */
- if (qsort(apps, numApps, sizeof(FullAppl), appCompare) != 0) {
- SysBeep(5);
- Quit();
- }
-
- if (doDeskDialog) DisposDialog(reading);
- SetCursor(&arrow);
-
- /* Display the modeless dialog box, and then start the event loop. */
- for(;;) {
- dPtr = DispChooseApp();
- op = EventLoop(dPtr, &evRec);
-
- LDispose(lh);
- DisposDialog(dPtr);
-
- if (op == I_DOCS) {
- SetPt(&pt, 70, 70);
- SFGetFile(pt, "", ListFileFilter, -1, NULL, NULL, &reply);
-
- /* Go around again to resolve the ambiguity about whatever Cancel means. */
- if (reply.good == FALSE) continue;
- }
- break;
- }
-
- if (op != I_QUIT) { /* we have something to launch. */
- /* Follow the example led by StdFile, and set up a HFS working directory. Then SetVol
- * the sucker and launch.
- */
- pb.ioCompletion = NULL;
- pb.ioNamePtr = NULL;
- pb.ioVRefNum = apps[theSelection].volID;
- pb.ioWDProcID = 'H∂R~'; /* application signature. */
- pb.ioWDDirID = apps[theSelection].dir;
-
- if (PBOpenWD(&pb, FALSE) != noErr) {
- StopAlert(R_CORRUPT, (ProcPtr)NULL );
- Quit();
- }
-
- vparm.ioVRefNum = pb.ioVRefNum;
- vparm.ioCompletion = NULL;
- vparm.ioNamePtr = NULL;
-
- if (PBSetVol(&vparm, FALSE) != noErr) {
- StopAlert(R_VOLPROBS, (ProcPtr)NULL );
- } else {
- /* Opened the folder, so we can launch. */
- if (miniFinder && CurApName[0] < 15) { /* i.e. don't rename! */
- /* Arrange to return in MiniFinder style. */
- BlockMove(CurApName, FinderName, CurApName[0] +1);
- } else {
- /* Make sure the Finder runs. */
- BlockMove(fName, FinderName, fName[0] + 1);
- }
-
- if (op == I_DOCS) {
- if (AppParmHandle != NULL) {
- /* Attach the document to the application parameters. Start by adjusting the
- * size of AppParmHandle to reflect the document name size, then copy in.
- */
- SetHandleSize(AppParmHandle, (Size)(13 + reply.fName[0]));
- if (MemErr != noErr) {
- SysBeep(1); SysBeep(1); Quit();
- }
- (*((OneArg **)AppParmHandle))->message = appOpen;
- (*((OneArg **)AppParmHandle))->count = 1;
- (*((OneArg **)AppParmHandle))->a.versNum = 0;
- BlockMove(reply.fName, (*((OneArg **)AppParmHandle))->a.fName,
- (Size)(reply.fName[0] + 1));
- (*((OneArg **)AppParmHandle))->a.fType = reply.fType;
- (*((OneArg **)AppParmHandle))->a.vRefNum = reply.vRefNum;
- }
- }
-
- /* We'd better check that it's there before we leap into the wild blue yonder... */
- v.fileParam.ioCompletion = NULL;
- v.fileParam.ioNamePtr = apps[theSelection].name;
- v.fileParam.ioVRefNum = pb.ioVRefNum;
- v.fileParam.ioFVersNum = 0;
- v.fileParam.ioFDirIndex = 0;
-
- if (PBGetFInfo(&v, FALSE) != noErr)
- StopAlert(R_CORRUPT, (ProcPtr)NULL );
- else
- Launch(0, apps[theSelection].name);
- }
- }
- Quit(); /* To the Finder. */
- }
-
- /*
- * EventLoop: sufficient event loop processing for modeless dialogs and desk accessories.
- */
-
- int
- EventLoop(dPtr, ev)
- register DialogPtr dPtr;
- register EventRecord *ev;
- {
- short itemHit;
- Handle theHand;
- Rect miniBox;
- short itemType;
- WindowPtr whichWindow;
- DialogPtr theDialog;
- register char theChar;
- Point whereIsIt;
- Point cell;
- GrafPtr savePort;
- Rect dragRect;
- Boolean editDim = TRUE; /* The edit menu starts out life as dimmed. */
-
- while(1) {
- SystemTask(); /* Clock keeps on ticking... */
-
- /* Menu consistency. The edit menu should be disabled unless the top window is a
- * system window.
- */
- if (dPtr == FrontWindow() ) { /* Disable them. */
- if (editDim == FALSE) {
- editDim = TRUE;
- DisableItem(GetMHandle(M_EDIT), 0);
- DrawMenuBar();
- }
- } else { /* Enable them. */
- if (editDim == TRUE) {
- editDim = FALSE;
- EnableItem(GetMHandle(M_EDIT), 0);
- DrawMenuBar();
- }
- }
-
- /* What's next? */
- (void)GetNextEvent(everyEvent, ev);
-
- /* First thing we do is check for dialog events. */
- if (IsDialogEvent(ev) == TRUE) {
-
- /* Do our own processing for stuff that DialogSelect won't do. */
- switch(ev->what) {
- case keyDown:
- case autoKey:
- theChar = ev->message & charCodeMask;
- if ((ev->modifiers & cmdKey) != 0) {
- if ((itemHit = DoCommand( MenuKey( theChar ))) != 0) return itemHit;
- } else {
- if ( (itemHit = DoChar(dPtr, theChar)) != 0) return itemHit;
- }
- continue;
- case activateEvt:
- LActivate(ev->modifiers&1, lh);
- break;
- }
-
- if (DialogSelect(ev, &theDialog, &itemHit) == TRUE) {
- GetPort(&savePort);
- SetPort(dPtr);
-
- switch(itemHit) {
- case I_MINIFINDER:
- miniFinder ^= 1;
- GetDItem(dPtr, I_MINIFINDER, &itemType, &theHand, &miniBox);
- SetCtlValue((ControlHandle)theHand, miniFinder);
- break;
- case I_APPS:
- whereIsIt = ev->where; /* don't trash original */
- GlobalToLocal( &whereIsIt );
-
- /* LClick will follow the mouse until it's released. */
-
- if (LClick(whereIsIt, 0, lh) == TRUE) { /* Double-click somewhere. */
- LPOINT(cell) = LLastClick(lh);
- theSelection = cell.v;
- return( I_RUN );
- }
-
- /* Single click. Find out where the selection is now. Can't use LLastClick
- * because we're interested in where the mouse was *released*.
- */
- cell.v = 0;
- cell.h = 0;
-
- if (LGetSelect( TRUE, &cell, lh) == FALSE) {
- /* Insufficient applications to activate scroll bar, and the click is in
- * the unused portion. This has got to be a floppy!
- */
- SysBeep(1);
- cell.v = theSelection;
- LSetSelect(TRUE, cell, lh);
- } else if (theSelection != cell.v) {
- /* New file type has been selected */
- theSelection = cell.v;
- }
- break;
- case I_RUN:
- case I_QUIT:
- case I_DOCS:
- return itemHit;
- default:
- break;
- }
- SetPort(savePort);
- }
- continue;
- }
-
- /* Doesn't belong to the dialog. Do the normal event processing. */
- switch (ev->what) {
- case mouseDown:
- switch (FindWindow( ev->where, &whichWindow )) {
- case inDesk:
- SysBeep(10);
- break;
- case inMenuBar:
- if ((itemHit = DoCommand( MenuSelect(ev->where))) != 0)return itemHit;
- case inSysWindow:
- SystemClick(ev, whichWindow );
- break;
- case inContent:
- if (whichWindow != FrontWindow())
- SelectWindow(whichWindow);
- break;
- case inDrag:
- if ( dPtr == whichWindow ) {
- dragRect = screenBits.bounds;
- InsetRect(&dragRect, 4, 4);
- dragRect.top += mbHeight;
- DragWindow( whichWindow, ev->where, &dragRect );
- }
- break;
- }
- break;
- case keyDown:
- case autoKey:
- theChar = ev->message & charCodeMask;
- if ((ev->modifiers & cmdKey) != 0) {
- if ( (itemHit = DoCommand( MenuKey( theChar ))) !=0) return itemHit;
- }
- break;
- }
- }
- }
-
- /*
- * DoChar: handles typing at the dialog.
- */
-
- int
- DoChar(dPtr, theChar)
- DialogPtr dPtr;
- unsigned char theChar;
- {
- int newSelect;
- GrafPtr savePort;
- Point cell;
-
- /* Is theChar return or enter? */
- if (theChar == 0x03 || theChar == 0x0d) return (I_RUN);
-
- /* Take the char, and find the first application that starts with this char. */
- GetPort(&savePort);
- SetPort(dPtr);
-
- if ((newSelect = StartsWith(theChar)) != theSelection) {
- /* We've moved. Unhighlight the old. */
- cell.h = 0;
- cell.v = theSelection;
- LSetSelect(FALSE, cell, lh);
-
- /* Highlight the new. */
- theSelection = cell.v = newSelect;
- LSetSelect(TRUE, cell, lh);
-
- /* And arrange to scroll until visible */
- LAutoScroll(lh);
- }
- SetPort(savePort);
- return 0;
- }
-
- /*
- * SetupDAs: setup the desk accessory, file and edit menus.
- */
-
- void
- SetupDAs()
- {
- if ( (mHandle = GetNewMBar(R_MENUBAR)) == NULL) Quit();
- SetMenuBar(mHandle);
-
- /* And add the desk accessories. */
- AddResMenu(GetMHandle(M_ABOUT), 'DRVR' );
-
- DrawMenuBar();
- }
-
- /*
- * DoCommand: fields menu commands.
- */
-
- int
- DoCommand( mResult)
- long mResult;
- {
- register int theItem;
- register int ret = 0;
- Str255 name;
-
- theItem = LoWord( mResult );
-
- switch (HiWord(mResult)) {
- case M_ABOUT:
- if (theItem == 1) { /* It's the about dialog box. */
- About();
- } else {
- GetItem(GetMHandle(M_ABOUT), theItem, name);
- OpenDeskAcc( &name );
- }
- break;
- case M_FILE:
- /* The items here are Attach Document, a separator, and Quit. */
- ret = (theItem == 1) ? I_DOCS : I_QUIT;
- break;
- case M_EDIT:
- /* They're only there for the desk accessories. */
- (void)SystemEdit(theItem-1);
- break;
- }
- HiliteMenu(0);
- return ret;
- }
-
- /*
- * About: field an "About HD Runner" request.
- */
-
- void
- About()
- {
- DialogPtr about = GetNewDialog(R_ABOUT, (Ptr)NULL, (WindowPtr)-1);
- short itemHit;
-
- OutlineButton(about, OK, I_ABOUTOUTLN); /* Highlight the default button. */
- ShowWindow(about);
-
- do {
- ModalDialog((ProcPtr)NULL, &itemHit);
- } while (itemHit != OK);
-
- DisposDialog(about);
- }
-
- /*
- * Quit: an ExitToShell that ensures that we go to the finder.
- */
-
- void
- Quit()
- {
- BlockMove(fName, FinderName, fName[0] + 1);
- ExitToShell();
- }
-
-
- /*
- * The file filtering routine. Watch the conditions -- it's FALSE to display.
- */
-
- pascal Boolean
- ListFileFilter(p)
- ParmBlkPtr p;
- {
- if ( p->fileParam.ioFlFndrInfo.fdCreator == apps[theSelection].creator &&
- p->fileParam.ioFlFndrInfo.fdType != 'APPL' ) {/* It matched! */
- return FALSE;
- } else {
- return TRUE; /* Do not display */
- }
- }
-
- /*
- * DispChooseApp: brings up the modeless dialog box.
- */
-
- DialogPtr
- DispChooseApp()
- {
- DialogPtr dPtr = GetNewDialog(R_DLOG, (Ptr)NULL, (WindowPtr)-1);
- Handle theHand;
- int itemType;
- Point csize, cell;
- Rect databounds;
- Rect listRect;
- register int i;
- Rect miniBox;
-
- /* Install the useritem drawing routine. */
- GetDItem(dPtr, I_APPS, &itemType, &theHand, &box);
- SetDItem(dPtr, I_APPS, itemType, ListDraw, &box);
-
- /* Initialize parameters for LNew */
- listRect = box; /* struct copy */
- InsetRect(&listRect, 1, 1); /* prepare for FrameRect */
- listRect.right -= 15; /* make room for horiz. scroll bar */
- SetRect(&databounds, 0, 0, 1, 0); /* list dimensions == 1 row. */
- csize.h = 0; /* init csize for defaults */
- csize.v = 0;
-
- /* Declare list and get a handle to it. */
- lh = LNew(&listRect, &databounds, csize, 0, dPtr, FALSE, FALSE, FALSE, TRUE);
-
- /* Specify click, drag, shift-click behavior */
- (*lh)->selFlags = lOnlyOne | lNoNilHilite | lNoExtend;
-
- /* Declare sufficient cells for our purpose. */
- LAddRow(numApps, 0, lh);
-
- /* Insert the application names into the cells. */
- cell.h = 0;
- cell.v = 0;
-
- for(i = 0; i < numApps; i++, cell.v++) {
- LSetCell(apps[i].name +1, (int)apps[i].name[0], cell, lh);
- }
-
-
- /* And set up the initial minifinder state. */
- GetDItem(dPtr, I_MINIFINDER, &itemType, &theHand, &miniBox);
- SetCtlValue((ControlHandle)theHand, miniFinder);
-
- /* Arrange for highlighting of the default button. */
- OutlineButton(dPtr, I_RUN, I_OUTLINE);
-
- /* And make everything visible */
- ShowWindow(dPtr);
-
- /* Enable drawing */
- LDoDraw(TRUE, lh);
-
- /* Mark the initial selection (first application, first time, then whatever it was we
- * cancelled an Attach Doc on.)
- */
- cell.h = 0;
- cell.v = theSelection;
- LSetSelect(TRUE, cell, lh);
-
- /* If we aren't at the beginning, arrange to scroll until visible */
- if (theSelection != 0) LAutoScroll(lh);
-
- return(dPtr);
- }
-
- /*
- * And the draw routine for the user item.
- */
-
- pascal void
- ListDraw(theDialog, theItem)
- DialogPtr theDialog;
- int theItem;
- {
- FrameRect(&box); /* Draw the containing box. */
-
- /* And tell the List Manager it's time to redraw. */
- LUpdate( ((WindowPeek)theDialog)->port.visRgn, lh);
- }
-
- /*
- * _Get1Resource: a GetResource for the current resource file only.
- */
-
- Handle
- _Get1Resource(res, id)
- ResType res;
- int id;
- {
- register Handle h;
-
- if (has64K) {
- h = GetResource(res, id);
- return( (HomeResFile(h) != CurMap) ? (Handle)NULL : h);
- } else {
- return (Get1Resource(res, id));
- }
- }
-
- /*
- * appCompare: qsort comparison function.
- */
-
- int
- appCompare(a1, a2)
- FullAppl *a1;
- FullAppl *a2;
- {
- Str255 name;
-
- /* Do a name comparison. */
- return (IUCompString(a1->name, a2->name));
- }
-
- /*
- * StartsWith: utility routine to do first character match for scrolling. Matches up to
- * MAX_MATCH characters and then clamps until timeout.
- */
-
- /* State data for multiple character match. */
- #define MAX_MATCH 4
- #define KEY_MAGNIFIER 2 /* The value used by StdFile. Thanks, MacNosy! */
-
- static int matchLen = 1;
- static char match[MAX_MATCH +1];
- static ulong lastKey = 0;
-
- int
- StartsWith(c)
- Byte c;
- {
- register int i;
- unsigned char pre[MAX_MATCH +1];
- register int cmpLen;
- register ulong thresh;
- register FullAppl *a;
-
- /* Check for cursor up, down. */
- if (c == cursDown) {
- /* Go up one, clamp at the end. */
- lastKey = Ticks;
- matchLen = 1;
- return ((theSelection == numApps -1)? theSelection : theSelection +1);
- }
-
- if (c == cursUp) {
- lastKey = Ticks;
- matchLen = 1;
-
- /* Go down one, clamp at the bottom. */
- return((theSelection == 0)? 0: theSelection -1);
- }
-
- if (lastKey != 0) {
- /* Have a timestamp. Are we still within the time interval for matching? */
- thresh = (ulong)Ticks - (ulong) (KeyThresh * KEY_MAGNIFIER);
-
- if (thresh < lastKey) {
- /* Within the interval. Check the MAX_MATCH clamp. */
- if (matchLen +1<= MAX_MATCH) {
- /* Add another character to the match string. */
- matchLen++;
- }
- } else {
- /* Waited too long. Reset the count. */
- matchLen = 1;
- }
- } else {
- /* Starting things off. */
- matchLen = 1;
- }
-
- lastKey = (ulong) Ticks;
- match[0] = matchLen;
- match[matchLen] = c;
- UprString(match, FALSE);
-
- /* Use the International Utilities package to handle case differences. */
- for(i = 0, a = apps; i < numApps; i++, a++) {
- cmpLen = MIN(matchLen, apps[i].name[0]);
- BlockMove(a->name +1, pre +1, cmpLen);
- pre[0] = cmpLen;
- UprString(pre, FALSE);
-
- if (pstrncmp(pre +1, match +1, cmpLen) >= 0) return i;
- }
- return (numApps -1);
- }
-
- /*
- * Pascal string version of strncmp. Used for comparing processed strings (UprString) & avoiding
- * the overhead of calling IUMagString. Not very general purpose - it assumes that each string is
- * at least n chars long.
- */
-
- int
- pstrncmp(s1, s2, n)
- register char *s1, *s2;
- register int n;
- {
- for (; --n && (*s1 == *s2); s1++, s2++) ;
-
- return (*s1 - *s2);
- }
-